﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Common.Utlis;
using S7.Net;
using S7.Net.Types;

namespace Common.Utils.S7Help
{
    public  static class S7DataItemHelp
    {
        public static DataItem GetDataItem<T, F>(Expression<Func<T, F>> expression, F f)where T:BaseDB
        {
            string propertyName = PropertyHelp.GetPropertyName(expression);
            return GetDataItem<T, F>(propertyName,f);
        }

        private static DataItem GetDataItem<T, F>(string propertyName, F f) where T : BaseDB
        {
            DataItem dataItem = new DataItem();
            dataItem.DataType = DataType.DataBlock;
            dataItem.DB = S7AttributeHelp.GetDB<T>();
            var adressInfo = S7AttributeHelp.GetAdress<T>(propertyName);
            dataItem.StartByteAdr=adressInfo.StartByteAdr;
            dataItem.BitAdr = adressInfo.BitAdr;
            dataItem.Value = f;
            dataItem.Count = 1;
            dataItem.VarType = GetVarType<F>(f);
            return dataItem;
        }

        public static VarType GetVarType<F>(F f)
        {
            VarType result = VarType.Byte;
            if (f is bool bol)
            {
                return VarType.Bit;
            }

            //短整型
            if (f is short)
            {
                return VarType.Int;
            }

            //浮点型
            if (f is float)
            {
                return VarType.Real;
            }

            //byte类型
            if (f is byte)
            {
                return VarType.Byte;
            }

            throw new Exception("不能解析的类型");
        }

        public static VarType GetVarType(Type type)
        {
            VarType result = VarType.Byte;
            if (type==typeof(bool))
            {
                return VarType.Bit;
            }

            //短整型
            if (type == typeof(short))
            {
                return VarType.Int;
            }

            //浮点型
            if (type == typeof(float))
            {
                return VarType.Real;
            }

            //byte类型
            if (type == typeof(byte))
            {
                return VarType.Byte;
            }

            throw new Exception("不能解析的类型");
        }

        public static int GetVarTypeLength(Type type)
        {
            if (type == typeof(bool))
            {
                return 1;
            }

            //短整型
            if (type == typeof(short))
            {
                return 2;
            }

            //浮点型
            if (type == typeof(float))
            {
                return 4;
            }

            //byte类型
            if (type == typeof(byte))
            {
                return 1;
            }

            throw new Exception("不能解析的类型");
        }

        public static int GetVarTypeLength<T>()
        {
            var type = typeof(T);
            if (type == typeof(bool))
            {
                return 1;
            }

            //短整型
            if (type == typeof(short))
            {
                return 2;
            }

            //浮点型
            if (type == typeof(float))
            {
                return 4;
            }

            //byte类型
            if (type == typeof(byte))
            {
                return 1;
            }

            throw new Exception("不能解析的类型");
        }

        /// <summary>
        /// 拿取整个类的DataItem
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static List<DataItem> GetReadDataItems<T>() where T : BaseDB
        {
            List<DataItem> result = new List<DataItem>();
            Type type = typeof(T);
          
           int db = S7AttributeHelp.GetDB<T>();
            PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                S7PropertyAttribute s7Property = (S7PropertyAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(S7PropertyAttribute));
                //不是S7的属性  直接跳过
                if (s7Property == null)
                {
                    continue;
                }
                DataItem dataItem = new DataItem();
                dataItem.DataType = DataType.DataBlock;
                dataItem.DB = db;
                dataItem.VarType = GetVarType(propertyInfo.PropertyType);
                dataItem.StartByteAdr = s7Property.StartByteAdr;
                dataItem.BitAdr = s7Property.BitAdr;
                dataItem.Count = 1;
                dataItem.Value = new object();
                result.Add(dataItem);
            }

            return result;
        }

        /// <summary>
        /// 拿取整个类的DataItem
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static List<PropertyDataItem> GetPropertyDataItems<T>() where T : BaseDB
        {
            List<PropertyDataItem> result = new List<PropertyDataItem>();
            Type type = typeof(T);

            int db = S7AttributeHelp.GetDB<T>();
            PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                S7PropertyAttribute s7Property = (S7PropertyAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(S7PropertyAttribute));
                //不是S7的属性  直接跳过
                if (s7Property == null)
                {
                    continue;
                }
                PropertyDataItem dataItem = new PropertyDataItem();
                dataItem.DataType = DataType.DataBlock;
                dataItem.DB = db;
                dataItem.VarType = GetVarType(propertyInfo.PropertyType);
                dataItem.StartByteAdr = s7Property.StartByteAdr;
                dataItem.BitAdr = s7Property.BitAdr;
                dataItem.Count = 1;
                dataItem.Value = new object();
                dataItem.PropertyInfo=propertyInfo;
                result.Add(dataItem);
            }

            return result;
        }

        /// <summary>
        /// 拿取整个类的DataItem
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static Dictionary<string,DataItem> GetReadDictDataItems<T>() where T : BaseDB
        {
            Dictionary<string, DataItem> result = new Dictionary<string, DataItem>(30);
            Type type = typeof(T);

            int db = S7AttributeHelp.GetDB<T>();
            PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);
            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                S7PropertyAttribute s7Property = (S7PropertyAttribute)Attribute.GetCustomAttribute(propertyInfo, typeof(S7PropertyAttribute));
                //不是S7的属性  直接跳过
                if (s7Property == null)
                {
                    continue;
                }
                DataItem dataItem = new DataItem();
                dataItem.DataType = DataType.DataBlock;
                dataItem.DB = db;
                dataItem.VarType = GetVarType(propertyInfo.PropertyType);
                dataItem.StartByteAdr = s7Property.StartByteAdr;
                dataItem.BitAdr = s7Property.BitAdr;
                dataItem.Count = 1;
                dataItem.Value = new object();
                string contract = $"{type.FullName}_{propertyInfo.Name}";
                result.TryAdd(contract, dataItem);
            }
            return result;
        }

        /// <summary>
        /// 拿取类中的部分信息
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static DataItem GetReadCalssItem<T>() where T : BaseDB
        {
            DataItem dataItem = new DataItem();
            Type type = typeof(T);

            int db = S7AttributeHelp.GetDB<T>();
            PropertyInfo[] propertyInfos = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);
            S7PropertyAttribute s7Property = (S7PropertyAttribute)Attribute.GetCustomAttribute(propertyInfos[0], typeof(S7PropertyAttribute));
            //不是S7的属性  直接跳过
            if (s7Property != null)
            {
                dataItem.DataType = DataType.DataBlock;
                dataItem.DB = db;
                dataItem.VarType = GetVarType(propertyInfos[0].PropertyType);
                dataItem.StartByteAdr = s7Property.StartByteAdr;
                dataItem.BitAdr = s7Property.BitAdr;
                dataItem.Count = 1;
            }
            return dataItem;

        }
    }
}
